package xj.model.uml;

public class Multiplicity {

  public static final int ANY = -1;

  public static final Multiplicity One = new Multiplicity(1, 1);

  public static final Multiplicity ZeroOrOne = new Multiplicity(0, 1);

  public static final Multiplicity OneToMany = new Multiplicity(1, ANY);

  public static final Multiplicity Many = new Multiplicity(ANY);

  public Multiplicity(int lower) {
    this(lower, lower);
  }

  public Multiplicity(int lower, int upper) {
    this.lower = lower;
    this.upper = upper;
  }

  public static String toString(Multiplicity m) {
    if (m != null) {
      return m.toString();
    }
    return null;
  }

  @Override
  public String toString() {
    if (lower == upper) {
      return boundString(lower);
    } else {
      if (lower < 0) {
	return "*";
      } else {
	if (lower == upper) {
	  return boundString(lower);
	} else {
	  return boundString(lower) + ".." + boundString(upper);
	}
      }
    }
  }

  private static String boundString(int i) {
    if (i >= 0) {
      return Integer.toString(i);
    } else {
      return "*";
    }
  }

  public static Multiplicity toMultiplicity(String s) {
    if (s != null) {
      s = s.trim();
      if (s.length() > 0) {
	if ("*".equals(s)) {
	  return Multiplicity.Many;
	}
	if ("1".equals(s)) {
	  return Multiplicity.One;
	} else if ("0..1".equals(s)) {
	  return Multiplicity.ZeroOrOne;
	} else if ("1..*".equals(s)) {
	  return Multiplicity.OneToMany;
	}

	int lower = -1, upper = -1;
	int i = s.indexOf("..");
	if (i < 0) {
	  lower = upper = boundValue(s);
	} else {
	  String s1 = s.substring(0, i).trim();
	  String s2 = s.substring(i + 2).trim();
	  lower = boundValue(s1);
	  upper = boundValue(s2);
	  if (lower == -1) {
	    upper = -1;
	  } else if (upper != -1 && lower > upper) {
	    upper = lower;
	  }
	}
	return new Multiplicity(lower, upper);
      }
    }
    return null;
  }

  private static int boundValue(String s) {
    if (!"*".equals(s)) {
      try {
	int v = Integer.parseInt(s);
	if (v >= 0) {
	  return v;
	}
      } catch (NumberFormatException e) {
      }
    }
    return -1;
  }

  @Override
  public boolean equals(Object other) {
    if (other instanceof Multiplicity) {
      Multiplicity m = (Multiplicity) other;
      return (lower == m.lower && upper == m.upper);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return (upper << 16) + lower; 
  }

  public boolean isMoreThanOne() {
    return (upper == -1 || upper > 1);
  }

  public int getLower() {
    return lower;
  }

  public int getUpper() {
    return upper;
  }

  protected int lower;

  protected int upper;

}
